Skip to content

feat: add Windows PowerShell scripts for cloud-deployment example#900

Open
spandey1702 wants to merge 4 commits into
a2aproject:mainfrom
spandey1702:fix/windows-support-issue-395
Open

feat: add Windows PowerShell scripts for cloud-deployment example#900
spandey1702 wants to merge 4 commits into
a2aproject:mainfrom
spandey1702:fix/windows-support-issue-395

Conversation

@spandey1702
Copy link
Copy Markdown

Add deploy.ps1, cleanup.ps1, and verify.ps1 as Windows equivalents of the existing bash scripts. Fixes #395.

  • deploy.ps1: full cluster setup (Kind, registry, Strimzi, PostgreSQL, Kafka, agent) with -ContainerTool docker|podman parameter
  • cleanup.ps1: reverse-order teardown with confirmation prompt
  • verify.ps1: health checks for all deployed components

Key translation notes:

  • Bash heredocs -> PowerShell here-strings piped to kubectl/docker stdin
  • export VAR=val -> $env:VAR = 'val'
  • grep/|| true -> -match / $LASTEXITCODE checks
  • sleep N -> Start-Sleep -Seconds N
  • curl -> curl.exe (avoids PowerShell Invoke-WebRequest alias)
  • SKIP_ENTITY_OPERATOR_WAIT and SKIP_AGENT_DEPLOY env vars supported

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces Windows PowerShell equivalents (deploy.ps1, cleanup.ps1, and verify.ps1) for the existing bash deployment scripts, along with updated documentation in the README.md. The code review feedback identifies several critical issues in the PowerShell scripts, primarily concerning Windows compatibility. These include a syntax error with here-string redirection, missing dependency checks for Maven and the container tool, and potential failures in string comparisons due to trailing carriage returns (\r) in output captured from external CLI tools like kubectl, docker/podman, and kind.

Comment thread examples/cloud-deployment/scripts/deploy.ps1
Comment thread examples/cloud-deployment/scripts/deploy.ps1 Outdated
Comment thread examples/cloud-deployment/scripts/deploy.ps1 Outdated
Comment thread examples/cloud-deployment/scripts/deploy.ps1
Comment thread examples/cloud-deployment/scripts/deploy.ps1 Outdated
Comment thread examples/cloud-deployment/scripts/verify.ps1 Outdated
Comment thread examples/cloud-deployment/scripts/verify.ps1 Outdated
Comment thread examples/cloud-deployment/scripts/verify.ps1 Outdated
@spandey1702 spandey1702 changed the title Add Windows PowerShell scripts for cloud-deployment example (#395) feat: add Windows PowerShell scripts for cloud-deployment example May 27, 2026
@spandey1702 spandey1702 force-pushed the fix/windows-support-issue-395 branch from 14da7a7 to 58311ac Compare May 27, 2026 19:36
@spandey1702
Copy link
Copy Markdown
Author

Addressed all Gemini review comments — added .Trim() for CRLF handling, \r? in the kind cluster regex, -match "^True\s*$" in verify.ps1, and dependency checks for Maven and the container tool.

@kabir
Copy link
Copy Markdown
Collaborator

kabir commented May 29, 2026

/gemini review

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces Windows PowerShell scripts (deploy.ps1, cleanup.ps1, and verify.ps1) as equivalents to the existing bash scripts for the cloud deployment example, along with corresponding updates to the README.md. The review feedback highlights several critical issues in the new PowerShell scripts: incorrect package names for the test client in deploy.ps1 and verify.ps1 that would cause a ClassNotFoundException, potential runtime exceptions from calling .Trim() on null values when inspecting containers, and a lack of error checking after kubectl wait commands which allows the deployment script to silently continue upon failure.

Comment thread examples/cloud-deployment/scripts/deploy.ps1
Comment thread examples/cloud-deployment/scripts/verify.ps1
Comment thread examples/cloud-deployment/scripts/deploy.ps1
Comment thread examples/cloud-deployment/scripts/deploy.ps1
Comment thread examples/cloud-deployment/scripts/deploy.ps1
Comment thread examples/cloud-deployment/scripts/deploy.ps1
Comment thread examples/cloud-deployment/scripts/deploy.ps1
@kabir
Copy link
Copy Markdown
Collaborator

kabir commented May 29, 2026

Hi @spandey1702 thank you.

I think it could be good to have these scripts tested on CI, similar to what we do for Linux in https://github.com/a2aproject/a2a-java/blob/main/.github/workflows/cloud-deployment-example.yml

AIUI GH Actions also provides Windows runners.

@spandey1702
Copy link
Copy Markdown
Author

Hi @kabir ,
Done — added .github/workflows/cloud-deployment-example-windows.yml mirroring the Linux workflow on a windows-latest runner.

@kabir
Copy link
Copy Markdown
Collaborator

kabir commented Jun 2, 2026

Hi @spandey1702 thank you!

Unfortunately it seems wee have a failure building the server, and something is failing in the BOM verification. I will see if I can add a job to test this on Windows and fix it. Then you can rebase.

@kabir
Copy link
Copy Markdown
Collaborator

kabir commented Jun 2, 2026

@spandey1702 This fixes the BOM verification on Windows #907

But I also added full testing on Windows. We will see if that passes!

…ct#395)

Add deploy.ps1, cleanup.ps1, and verify.ps1 as Windows equivalents
of the existing bash scripts. Fixes a2aproject#395.

- deploy.ps1: full cluster setup (Kind, registry, Strimzi, PostgreSQL,
  Kafka, agent) with -ContainerTool docker|podman parameter
- cleanup.ps1: reverse-order teardown with confirmation prompt
- verify.ps1: health checks for all deployed components

Key translation notes:
- Bash heredocs -> PowerShell here-strings piped to kubectl/docker stdin
- export VAR=val -> $env:VAR = 'val'
- grep/|| true -> -match / $LASTEXITCODE checks
- sleep N -> Start-Sleep -Seconds N
- curl -> curl.exe (avoids PowerShell Invoke-WebRequest alias)
- SKIP_ENTITY_OPERATOR_WAIT and SKIP_AGENT_DEPLOY env vars supported

Also updates README.md with Windows quick-start instructions,
PowerShell execution policy note, and updated project structure table.
- Add missing dependency checks for Maven and container tool
- Trim docker/podman inspect output to handle CRLF on Windows
- Use \r? in kind cluster regex to match Windows line endings
- Use -match '^True\s*$' instead of -eq 'True' in verify.ps1
  to handle trailing whitespace/carriage returns in kubectl output
Adds a GitHub Actions workflow on windows-latest that mirrors the
existing Linux cloud-deployment-example.yml, running deploy.ps1,
verify.ps1, and cleanup.ps1 on a Windows runner.

Adds a -Force switch to cleanup.ps1 to skip the interactive
Read-Host confirmation prompt in CI environments.
When the Kind cluster is not reachable (e.g. failed deploy in CI),
kubectl falls back to localhost:8080 and all delete commands fail
with connection errors. Added a cluster-info connectivity check before
resource deletion — if unreachable, skip straight to kind delete cluster
since resources are removed with the cluster anyway.
@kabir kabir force-pushed the fix/windows-support-issue-395 branch from 898ce65 to 1e2c5be Compare June 2, 2026 10:51
@kabir
Copy link
Copy Markdown
Collaborator

kabir commented Jun 2, 2026

@spandey1702 I merged the Windows fix and have rebased your PR on the latest main. Let's see what CI says 🤞

@kabir
Copy link
Copy Markdown
Collaborator

kabir commented Jun 3, 2026

/gemini review

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces Windows-compatible PowerShell scripts (deploy.ps1, cleanup.ps1, and verify.ps1) as equivalents to the existing bash scripts for deploying, cleaning up, and verifying the A2A Cloud example deployment, alongside corresponding documentation updates in the README.md. The review feedback highlights several robustness issues in the new PowerShell scripts. These include potential MethodInvocationException errors when calling .Trim() on commands that might return null, a missing Start-Sleep in the Kafka deployment wait loop that causes premature timeouts, unhandled carriage returns (\r) in node names on Windows, and a logic flaw in cleanup.ps1 when kubectl is missing from the system PATH.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment on lines +71 to +72
$running = (& $ContainerTool inspect -f '{{.State.Running}}' $RegName 2>$null).Trim()
if ($running -ne "true") {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

Calling .Trim() directly on the output of the container tool inspect command will throw a MethodInvocationException ("You cannot call a method on a null-valued expression") on the very first run of the script because the kind-registry container does not exist yet, causing the command to return $null.

To prevent this, cast the command output to [string] before calling .Trim(). This is safe and fully compatible with PowerShell 5.1+.

$running = [string](& $ContainerTool inspect -f '{{.State.Running}}' $RegName 2>$null)
if ($running.Trim() -ne "true") {

Comment on lines +281 to +298
for ($i = 1; $i -le 60; $i++) {
Write-Host "Checking Kafka status (attempt $i/60)..."
kubectl get kafka -n kafka -o wide 2>$null
kubectl get pods -n kafka -l strimzi.io/cluster=a2a-kafka 2>$null

$null = kubectl wait --for=condition=Ready kafka/a2a-kafka -n kafka --timeout=10s 2>$null
if ($LASTEXITCODE -eq 0) {
Write-Host "✓ Kafka deployed" -ForegroundColor Green
break
}

if ($i -eq 60) {
Write-Host "ERROR: Timeout waiting for Kafka" -ForegroundColor Red
kubectl describe kafka/a2a-kafka -n kafka
kubectl get events -n kafka --sort-by='.lastTimestamp'
exit 1
}
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

In the else block of the Kafka deployment wait loop, there is no Start-Sleep call. If kubectl wait fails immediately (for example, if the kafka/a2a-kafka resource has not been created yet), the loop will spin extremely fast, executing 60 times in less than a second and failing with a timeout error.

Add Start-Sleep -Seconds 5 at the end of the loop iteration, matching the behavior of the if block's loop.

    for ($i = 1; $i -le 60; $i++) {
        Write-Host "Checking Kafka status (attempt $i/60)..."
        kubectl get kafka -n kafka -o wide 2>$null
        kubectl get pods -n kafka -l strimzi.io/cluster=a2a-kafka 2>$null

        $null = kubectl wait --for=condition=Ready kafka/a2a-kafka -n kafka --timeout=10s 2>$null
        if ($LASTEXITCODE -eq 0) {
            Write-Host "✓ Kafka deployed" -ForegroundColor Green
            break
        }

        if ($i -eq 60) {
            Write-Host "ERROR: Timeout waiting for Kafka" -ForegroundColor Red
            kubectl describe kafka/a2a-kafka -n kafka
            kubectl get events -n kafka --sort-by='.lastTimestamp'
            exit 1
        }

        Start-Sleep -Seconds 5
    }

Comment on lines +124 to +125
$networkInfo = (& $ContainerTool inspect -f '{{json .NetworkSettings.Networks.kind}}' $RegName 2>$null).Trim()
if ($networkInfo -eq "null" -or [string]::IsNullOrEmpty($networkInfo)) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Similar to the registry running check, calling .Trim() directly on the output of the inspect command can throw a MethodInvocationException if the command returns $null.

Cast the output to [string] first to ensure safe trimming.

$networkInfo = [string](& $ContainerTool inspect -f '{{json .NetworkSettings.Networks.kind}}' $RegName 2>$null)
$networkInfo = $networkInfo.Trim()
if ($networkInfo -eq "null" -or [string]::IsNullOrEmpty($networkInfo)) {

Comment on lines +114 to +117
foreach ($node in (kind get nodes)) {
& $ContainerTool exec $node mkdir -p $RegistryDir
"[host.`"http://${RegName}:5000`"]" | & $ContainerTool exec -i $node sh -c "cat > ${RegistryDir}/hosts.toml"
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

On Windows, external command outputs (like kind get nodes) often contain trailing carriage return characters (\r). If $node contains a trailing \r, executing & $ContainerTool exec $node ... will fail because the container name will be invalid.

Trim each node name to ensure compatibility on Windows.

foreach ($node in (kind get nodes)) {
    $node = $node.Trim()
    if ([string]::IsNullOrEmpty($node)) { continue }
    & $ContainerTool exec $node mkdir -p $RegistryDir
    "[host.""http://${RegName}:5000"""]" | & $ContainerTool exec -i $node sh -c "cat > ${RegistryDir}/hosts.toml"
}

Comment on lines +47 to +76
$null = kubectl cluster-info 2>$null
if ($LASTEXITCODE -eq 0) {
Write-Host "✓ Cluster reachable, deleting resources..." -ForegroundColor Green

Write-Host ""
Write-Host "Deleting A2A Agent..."
kubectl delete -f "..\k8s\05-agent-deployment.yaml" --ignore-not-found=true

Write-Host ""
Write-Host "Deleting ConfigMap..."
kubectl delete -f "..\k8s\04-agent-configmap.yaml" --ignore-not-found=true

Write-Host ""
Write-Host "Deleting Kafka topic..."
kubectl delete -f "..\k8s\03-kafka-topic.yaml" --ignore-not-found=true

Write-Host ""
Write-Host "Deleting Kafka..."
kubectl delete -f "..\k8s\02-kafka.yaml" --ignore-not-found=true

Write-Host ""
Write-Host "Deleting PostgreSQL..."
kubectl delete -f "..\k8s\01-postgres.yaml" --ignore-not-found=true

Write-Host ""
Write-Host "Deleting namespace..."
kubectl delete -f "..\k8s\00-namespace.yaml" --ignore-not-found=true
} else {
Write-Host "⚠ Cluster not reachable, skipping resource deletion — resources will be removed with the cluster." -ForegroundColor Yellow
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

If kubectl is not installed or not in the system PATH, calling kubectl cluster-info will throw a command-not-found exception in PowerShell. Since $LASTEXITCODE is not updated when a command-not-found error occurs, it will retain whatever value it had from the parent session. If that value was 0, the script will incorrectly enter the if block and attempt to run multiple kubectl delete commands, throwing a series of noisy errors.

Check if kubectl is available using Get-Command before executing it, similar to how it is done in deploy.ps1.

if (Get-Command kubectl -ErrorAction SilentlyContinue) {
    $null = kubectl cluster-info 2>$null
    if ($LASTEXITCODE -eq 0) {
        Write-Host "✓ Cluster reachable, deleting resources..." -ForegroundColor Green

        Write-Host ""
        Write-Host "Deleting A2A Agent..."
        kubectl delete -f "..\k8s\05-agent-deployment.yaml" --ignore-not-found=true

        Write-Host ""
        Write-Host "Deleting ConfigMap..."
        kubectl delete -f "..\k8s\04-agent-configmap.yaml" --ignore-not-found=true

        Write-Host ""
        Write-Host "Deleting Kafka topic..."
        kubectl delete -f "..\k8s\03-kafka-topic.yaml" --ignore-not-found=true

        Write-Host ""
        Write-Host "Deleting Kafka..."
        kubectl delete -f "..\k8s\02-kafka.yaml" --ignore-not-found=true

        Write-Host ""
        Write-Host "Deleting PostgreSQL..."
        kubectl delete -f "..\k8s\01-postgres.yaml" --ignore-not-found=true

        Write-Host ""
        Write-Host "Deleting namespace..."
        kubectl delete -f "..\k8s\00-namespace.yaml" --ignore-not-found=true
    } else {
        Write-Host "⚠ Cluster not reachable, skipping resource deletion — resources will be removed with the cluster." -ForegroundColor Yellow
    }
} else {
    Write-Host "⚠ kubectl not found, skipping resource deletion — resources will be removed with the cluster." -ForegroundColor Yellow
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feat]: Set up Kubernetes example to also run on Windows.

2 participants